<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
use App\Models\MoneyBook;
use App\Models\MoneyTransaction;
use App\Models\MoneyCategory;
use App\Services\OcrService;
use App\Services\AudioTranscribeService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use EasyWeChat\OfficialAccount\Application;

class ProcessWechatMessageJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $message;
    protected $user;
    protected $moneyBook;
    protected $wxapp;

    /**
     * 创建新的任务实例
     */
    public function __construct($message, User $user, MoneyBook $moneyBook)
    {
        $this->message = $message;
        $this->user = $user;
        $this->moneyBook = $moneyBook;
        $this->wxapp = new Application(config('wechat.official_account.default'));
    }

    /**
     * 执行任务
     */
    public function handle()
    {
        try {
            $result = $this->processMessage();
            if (is_string($result)) $this->sendCustomerServiceMessage($result);
            else $this->sendTransactionSuccessTemplateMessage($result);
        } catch (\Exception $e) {
            Log::error('微信消息异步处理失败：' . exception_to_string($e));
            $this->sendCustomerServiceMessage('处理失败，请稍后重试。');
        }
    }

    /**
     * 处理微信消息
     */
    private function processMessage()
    {
        // 加载分类关系
        $this->moneyBook->load(['categories.subCategories']);

        $text = '';
        $imagePath = '';
        $textPrefix = '';
        $data2 = [];

        // 处理不同类型的消息
        switch ($this->message['MsgType']) {
            case 'text':
                $textPrefix = '微信消息：';
                $text = $this->message['Content'];
                $data2 = ['text' => $textPrefix.mb_substr(trim($text), 0, 150)];
                break;

            case 'voice':
                $textPrefix = '微信语音：';
                try {
                    // 下载语音文件
                    $media = $this->wxapp->getClient();
                    $response = $media->get('/cgi-bin/media/get', [
                        'query' => [
                            'media_id' => $this->message['MediaId']
                        ]
                    ]);
                    $voiceContent = $response->getContent();

                    // 保存语音文件
                    $voiceFilePath = 'voice_messages/' . date('Ym') . '/wechat_' . $this->message['MediaId'] . '.amr';
                    Storage::disk('public')->put($voiceFilePath, $voiceContent);
                    $fullPath = Storage::disk('public')->path($voiceFilePath);

                    // 使用语音转文本服务
                    try {
                        $text = $this->message['Recognition'] ?? '';
                        if (! $text) {
                            $audioTranscribeService = new AudioTranscribeService();
                            $transcribeResult = $audioTranscribeService->transcribeAudio($fullPath);
                            if (!$transcribeResult['success'] || empty($transcribeResult['result'])) {
                                Log::error('语音转文本失败', ['result' => $transcribeResult]);
                                return '语音识别失败，请重新发送或尝试发送文字消息。';
                            }
                            // 获取转录文本
                            $text = trim($transcribeResult['result'][0] ?? '');
                        }

                        if (! $text) return '语音识别失败，请重新发送或尝试发送文字消息。';

                        $data2 = [
                            'text' => $textPrefix.mb_substr(trim($text), 0, 150),
                            'audio' => $voiceFilePath,
                        ];
                    } catch (\Exception $e) {
                        Log::error('微信语音处理失败0：' . exception_to_string($e));
                        return '语音识别失败，请重新发送或尝试发送文字消息。';
                    }
                } catch (\Exception $e) {
                    Log::error('微信语音处理失败：' . exception_to_string($e));
                    return '语音处理失败，请重新发送。';
                }
                break;

            case 'image':
                try {
                    // 下载图片
                    $media = $this->wxapp->getClient();
                    $response = $media->get('/cgi-bin/media/get', [
                        'query' => [
                            'media_id' => $this->message['MediaId']
                        ]
                    ]);
                    $imageContent = $response->getContent();

                    // 验证图片
                    $tempFile = tempnam(sys_get_temp_dir(), 'wechat_img_');
                    file_put_contents($tempFile, $imageContent);

                    // 检查文件大小（最大5MB）
                    $fileSize = filesize($tempFile);
                    if ($fileSize > 5 * 1024 * 1024) {
                        @unlink($tempFile); // 删除临时文件
                        return '图片大小不能超过5MB，请重新发送较小的图片。';
                    }

                    // 检查文件类型
                    $finfo = new \finfo(FILEINFO_MIME_TYPE);
                    $mimeType = $finfo->file($tempFile);
                    $allowedTypes = ['image/jpeg', 'image/jpg', 'image/png'];

                    if (!in_array($mimeType, $allowedTypes)) {
                        @unlink($tempFile); // 删除临时文件
                        return '只支持JPEG、JPG和PNG格式的图片，请重新发送正确格式的图片。';
                    }

                    @unlink($tempFile); // 删除临时文件

                    // 保存图片
                    $imagePath = 'transaction_images/' . date('Ym') . '/wechat_' . $this->message['MediaId'] . '.jpg';
                    Storage::disk('public')->put($imagePath, $imageContent);

                    // OCR识别图片文字
                    $ocrService = new OcrService();
                    $text = $ocrService->recognizeImage($imagePath);

                    if (empty($text)) {
                        return '图片识别失败，请重新发送或发送文字消息。';
                    }
                    $data2 = ['image' => $imagePath,];
                } catch (\Exception $e) {
                    Log::error('微信图片处理失败：' . exception_to_string($e));
                    return '图片处理失败，请重新发送。';
                }
                break;

            default:
                return '暂不支持此类型消息，请发送文字、语音或图片。';
        }

        // 使用AI提炼信息
        $format = MoneyTransaction::formatTextByAi($text, $this->moneyBook);

        if (!$format || !isset($format['res']) || isset($format['res']['error'])) {
            Log::error('AI记账失败：'.json_encode($format, JSON_UNESCAPED_UNICODE));
            return $format['res']['error'] ?? '无法识别记账信息，请稍后重试';
        }
        $format = $format['res'];

        // 将字符串类型转换为数字常量
        $typeValue = $format['type'] === 'income' ? MoneyCategory::TYPE_INCOME : MoneyCategory::TYPE_EXPENSE;

        // 直接保存交易记录
        $data = [
            'book_id' => $this->moneyBook->id,
            'user_id' => $this->user->id,
            'category_id' => $format['category_id'],
            'sub_category_id' => $format['sub_category_id'],
            'type' => $typeValue,
            'amount' => $format['amount'],
            'transaction_date' => $format['date'],
            'description' => $format['description'],
        ];
        if ($data2) $data += $data2;
        $transaction = MoneyTransaction::create($data);

        // 如果是非会员，增加使用次数记录
        if (!$this->user->isMember()) {
            $featureType = '';
            switch ($this->message['MsgType']) {
                case 'text':
                    $featureType = 'record_by_text';
                    break;
                case 'voice':
                    $featureType = 'record_by_audio';
                    break;
                case 'image':
                    $featureType = 'record_by_image';
                    break;
            }

            // 记录使用次数
            $this->user->incrementUsageCount($featureType);
        }

//        $typeText = $format['type'] === 'income' ? '收入' : '支出';
//        $date = substr($format['date'], 0, 10);

        // 发送模板消息通知
        $transaction['category'] = $format['category'];

//        $info = "记账成功！\n" .
//            "类型：{$typeText}\n" .
//            "金额：{$transaction['amount']}元\n" .
//            "分类：{$format['category']}\n" .
//            "日期：{$date}\n" .
//            "备注：{$transaction['description']}\n" .
//            "编辑地址：".route('transaction.edit', ['id'  => $transaction['id']]);
        return $transaction;
    }

    /**
     * 发送客服消息
     */
    private function sendCustomerServiceMessage($content)
    {
        try {
            $client = $this->wxapp->getClient();
            $response = $client->postJson('/cgi-bin/message/custom/send', [
                "touser" => $this->message['FromUserName'],
                "msgtype" => "text",
                "text" => [
                    "content" => $content
                ]
            ]);
            $res_str = $response->getContent();
            $res = json_decode($res_str, true);
            if ($res['errcode'] != 0) {
                Log::error('发送客服消息失败：' . $res_str);
            }
//            log_record($res);
        } catch (\Exception $e) {
            Log::error('发送客服消息失败：' . exception_to_string($e));
        }
    }

    /**
     * 发送记账成功模板消息
     *
     * @param array $transaction 交易记录
     * @param array $format 格式化后的交易信息
     * @return void
     */
    private function sendTransactionSuccessTemplateMessage($transaction)
    {
        try {
            // 模板ID：FD5lAagHN_b13AfA960QTtnlDUY5X99UcRD9OLZ9x40
            $templateId = 'FD5lAagHN_b13AfA960QTtnlDUY5X99UcRD9OLZ9x40';
            $typeText = MoneyTransaction::type_map[$transaction['type']];

            $client = $this->wxapp->getClient();
            $response = $client->postJson('/cgi-bin/message/template/send', [
                'touser' => $this->message['FromUserName'],
                'template_id' => $templateId,
                'url' => route('transaction.show', ['id' => $transaction['id']]),
                'data' => [
                    'const40' => [
                        'value' => $typeText
                    ],
                    'thing3' => [
                        'value' => $transaction['category']
                    ],
                    'amount4' => [
                        'value' => $transaction['amount']
                    ],
                    'time8' => [
                        'value' => $transaction['transaction_date']->format('Y-m-d'),
                    ],
                    'thing22' => [
                        'value' => mb_substr($transaction['description'], 0, 20) ?: '-'
                    ]
                ]
            ]);

            $res_str = $response->getContent();
            $res = json_decode($res_str, true);
            if ($res['errcode'] != 0) {
                Log::error('发送记账成功模板消息失败：' . $res_str);
            }
        } catch (\Exception $e) {
            Log::error('发送记账成功模板消息失败：' . exception_to_string($e));
        }
    }
}
